package org.wattdepot.modbus.meter.yokogawa;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.wimpi.modbus.net.ModbusTCPListener;
import net.wimpi.modbus.procimg.SimpleProcessImage;
import net.wimpi.modbus.procimg.SimpleRegister;
import net.wimpi.modbus.core.Modbus;
import net.wimpi.modbus.core.ModbusCoupler;
import org.wattdepot.resource.sensordata.jaxb.SensorData;
import org.wattdepot.simulation.dorm.Dorm;
import org.wattdepot.simulation.basic.SystemTime;
import org.wattdepot.simulation.core.Simulation;
import org.wattdepot.client.WattDepotClient;
import javax.swing.Timer;

/**
 * A TCP/IP server program hold particular data such as power, date, time, and energy usage. The
 * server is automated to update every second.
 * 
 * @author Alan Lee
 * 
 */
public class YokogawaSlave {
  /**Pattern to match IP address.*/
  private static final String IPADDRESS_PATTERN = 
    "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
  
  /**
   * Main program to run Mod-Bus automation.
   * 
   * @param args not applicable
   */
  public static void main(String[] args) {
    

    
      final Simulation m_Random = new Dorm();
      final WattDepotClient client;
      final String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
      // Important instances and variables
      ModbusTCPListener listener = null;
      final SimpleProcessImage spi = new SimpleProcessImage();
      
      //Test WattDepot server connection
      client = new WattDepotClient(hostUri);
      if (!client.isHealthy()) {
        System.out.println("Failed to connect to " + client.getWattDepotUri());
        return;
      }
      // Indicate successful connection.
      System.out.println("Connected to " + client.getWattDepotUri());
      
      //Retrieve latest energy usage from WattDepot.
      try {
        SensorData serverData = client.getLatestSensorData("SIM_ACUVIM");
        double conversion = Double.parseDouble(serverData.getProperty("energyConsumedToDate"));
        int data = (int)(conversion * 10);
        m_Random.setServerEnergy(data);
      }
      catch (Exception ex) {
        ex.printStackTrace();
      }
      
      
      // 1. Set port number and address
      System.out.println("Set IP address for meter: ");
      Scanner input = new Scanner(System.in);
      String astr = input.nextLine();
      Pattern regx = Pattern.compile(IPADDRESS_PATTERN);
      Matcher match = regx.matcher(astr);
      if (!match.find()) {
        System.err.println("Invalid IP address.  Check your IP address.  Good-Bye.");
        return;
      }
      try {
        InetAddress addr = InetAddress.getByName(astr);
      
        int port = Modbus.DEFAULT_PORT;
        
        
        // 2. Create a listener with 3 threads in pool
        listener = new ModbusTCPListener(3);
        listener.setPort(port);
        listener.setAddress(addr);
        listener.start();
      }
      catch (Exception ex) {
        ex.printStackTrace();
      }

      // 3. Prepare a process image
      final SimpleRegister[] test = new SimpleRegister[20000];
      int count = 0;

      while (count < test.length) {
        test[count] = new SimpleRegister(0);
        spi.addRegister(test[count]);
        count++;
      }

      // Debugging
      System.out.println("Debugging Initial Register[0] = " + spi.getRegister(0).getLowValue());

      // 4. Set the image on the coupler
      ModbusCoupler.getReference().setProcessImage(spi);
      ModbusCoupler.getReference().setMaster(false);
      ModbusCoupler.getReference().setUnitID(15);
      
      
      System.out.println("Modbus Slave activated...");
      int delay = 1000; // milliseconds
  try {
      ActionListener taskPerformer = new ActionListener() {

        public void actionPerformed(ActionEvent evt) {
          final SystemTime clock = new SystemTime();
          test[4160].setLowValue(clock.getYear());
          test[4161].setLowValue(clock.getMonth());
          test[4162].setLowValue(clock.getDay());
          test[4163].setLowValue(clock.getHour());
          test[4164].setLowValue(clock.getMinute());
          test[4165].setLowValue(clock.getSecond());

          m_Random.createRandomValue();
          test[16418].setHighValue(m_Random.getIntBits());
          test[16419].setLowValue(m_Random.getIntBits());
          m_Random.createRandomPT1Value();
          test[4101].setHighValue(m_Random.getBitsForPT());
          test[4102].setLowValue(m_Random.getBitsForPT());
          m_Random.createRandomPT2Value();
          test[4103].setLowValue(m_Random.getPT2());
          test[4104].setLowValue(m_Random.createRandomCT1Value());
          test[4105].setLowValue(m_Random.createRandomCT2Value());
          // System.out.println(kW.getValue());
          // Get new energy total
          m_Random.totalAccumulatedEnergy(test[16418].getHighValue() + test[16419].getLowValue());
          test[16465].setLowValue(m_Random.getEnergy());
          test[16464].setLowValue(m_Random.getLimit());
          System.out.println("-------------------" + "-------------------");
          int counter = 4160;
          while (counter < 4166) {
            System.out.println("Register[" + counter + "] = "
                + spi.getRegister(counter).getLowValue());
            counter++;
          }
          System.out.println("Register[4101] = "
              + Float.intBitsToFloat(spi.getRegister(4101).getHighValue()) + "V");
          System.out.println("Register[4102] = "
              + Float.intBitsToFloat(spi.getRegister(4102).getLowValue()) + "V");
          counter = 4103;
          System.out.println("Register[4103] = " + spi.getRegister(4103).getLowValue() + "V");
          System.out.println("Register[4104] = " + spi.getRegister(4104).getLowValue() + "A");
          System.out.println("Register[4105] = " + spi.getRegister(4105).getLowValue() + "A");
          System.out.println("Register[16418] = "
              + Float.intBitsToFloat(spi.getRegister(16418).getHighValue()) + "W");
          System.out.println("Register[16419] = "
              + Float.intBitsToFloat((spi.getRegister(16419).getLowValue())) + "W");
          System.out.println("Register[16464] = " + spi.getRegister(16464).getLowValue() + "kWh");
          System.out.println("Register[16465] = " + spi.getRegister(16465).getLowValue() + "kWh");

        }
      };
      new Timer(delay, taskPerformer).start();
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}
